#include "radiobll.h"
#include <QThread>
#include <QThreadPool>
#include <QDebug>
#include <QRunnable>
#include <QDateTime>
#include <QMutex>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QEventLoop>
#include <QString>
#include <QScriptEngine>
#include <QScriptValueIterator>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QMutex>
#include "EZTallyDictionary.h"
#include "radiomodel.h"
#include "radioplaylistmodel.h"



RadioBll::RadioBll(QObject *parent) :
    QObject(parent)
{
    _delegate = 0;
//    _songReply = 0;
    _curRadio = 0;
    _songhttp = 0;
//    connect(&_netManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(getSongsFinish_SLOT(QNetworkReply*)));
}


RadioBll::~RadioBll()
{
//    _songReply = 0;
    if(_songhttp){
        _songhttp->Release();
        _songhttp = 0;
    }
    disconnect(this);
}

RadioPlayListModel* RadioBll::playListWithRadio(RadioModel *radio,bool isGetSong)
{
    if(radio==0 ){
        return 0;
    }
    static EZTally::EZTallyDictionary<const std::string,RadioPlayListModel*> *dic=0;
    static QMutex mutex;
    mutex.lock();
    if(dic==0){
        dic = new EZTally::EZTallyDictionary<const std::string,RadioPlayListModel*>();
    }

    RadioPlayListModel *playList = dic->ObjectForKey(radio->radioKey().toStdString());
    if(playList==0){
        playList = new RadioPlayListModel();
        playList->setRadio(radio);
        dic->SetObjectForKey(radio->radioKey().toStdString(),playList);
        playList->Release();
    }
    if(isGetSong == true && playList->count()==0){
        playList->wantGetMoreSong();
    }

    mutex.unlock();
    return playList;
}
int RadioBll::getSongs(int songCount, const QString &offset)
{
    if(_curRadio==0){
        return -1;
    }
//    if(_songReply){
//        return 1;
//    }

//

//    QByteArray byteBody;
//    QString bodyStr("fmcount=%1&fmtype0=%2&fmid0=%3&size=%4&cmd=12&pid=ios&ver=4000");
//    bodyStr =  bodyStr.arg(1).arg(_curRadio->getFmtype()).arg(_curRadio->getFmid()).arg(songCount);
////    &offset0=%4&offset=%5
//    bodyStr.append("&offset0="+useOffset +"&offset="+useOffset);
//    byteBody.append(bodyStr);
////    qDebug() << useOffset;
////    qDebug() << bodyStr;
//
//    QUrl url(urlStr);
//    QNetworkRequest request(url);
//    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded; charset=utf-8"));

//    _songReply =  _netManager.post(request,byteBody);

    if(_songhttp){
        return 1;
    }
    QString urlStr("http://lib3.service.kugou.com/index.php");
    QString useOffset = offset.isEmpty()? _curRadio->offset():offset;
    _songhttp = new EZQHTTPNS::EZQHttp();
    _songhttp->setUrl(urlStr);
    _songhttp->setMethod("POST");
    _songhttp->addPostValue("fmcount","1");
    _songhttp->addPostValue("fmtype0",QString("%1").arg(_curRadio->getFmtype()) );
    _songhttp->addPostValue("fmid0",QString("%1").arg(_curRadio->getFmid()) );
    _songhttp->addPostValue("size",QString("%1").arg(songCount));
    _songhttp->addPostValue("cmd","12");
    _songhttp->addPostValue("pid","ios");
    _songhttp->addPostValue("ver","4000");
    _songhttp->addPostValue("offset0",useOffset);
    _songhttp->addPostValue("offset",useOffset);
    _songhttp->setHeader(QNetworkRequest::ContentTypeHeader,"application/x-www-form-urlencoded; charset=utf-8");
    connect(_songhttp,SIGNAL(finish()),this,SLOT(getSongFinish_SLOT()));
    _songhttp->startAsync();

    return 0;

}
void RadioBll::getSongFinish_SLOT()
{
    EZQHTTPNS::EZQHttp *http = (EZQHTTPNS::EZQHttp*)sender();
    if(http != _songhttp){
        return;
    }
    QByteArray bytes = http->responseBytes();

    QString *offset = 0;
    int error = 0;
    EZTally::EZTallyAutoPtr ptr = RadioBll::ParseRadioSongsFromNetstr(bytes,&error,&offset);
    if(error==0){
        _curRadio->setOffset(*offset);
        delete offset;
    }
    EZTally::EZTallyArray<SongModel*> *songs = (EZTally::EZTallyArray<SongModel*>*)ptr.Get();
    if(_delegate){
        _delegate->onGetSongsFinish(this,songs,error);
    }

    _songhttp->Release();
    _songhttp = 0;
//    qDebug() << _curRadio->getFmname() << _curRadio->offset() << "get song count:" << songs->Count();
    emit getSongsFinish_SIG(ptr,error);


//    delegate()
}

//void RadioBll::getSongsFinish_SLOT(QNetworkReply *reply)
//{
//    if(_songReply != reply){
//        return;
//    }
//    QByteArray bytes = reply->readAll();

//    QString *offset = 0;
//    int error = 0;
//    EZTally::EZTallyAutoPtr ptr = RadioBll::ParseRadioSongsFromNetstr(bytes,&error,&offset);
//    if(error==0){
//        _curRadio->setOffset(*offset);
//        delete offset;
//    }
//    EZTally::EZTallyArray<SongModel*> *songs = (EZTally::EZTallyArray<SongModel*>*)ptr.Get();
//    if(_delegate){
//        _delegate->onGetSongsFinish(this,songs,error);
//    }
////    qDebug() << _curRadio->getFmname() << _curRadio->offset() << "get song count:" << songs->Count();
//    emit getSongsFinish_SIG(ptr,error);
//    _songReply = 0;
//}



RadioModel *RadioBll::curRadio() const
{
    return _curRadio;
}

void RadioBll::setCurRadio(RadioModel *curRadio)
{
    if(curRadio){
        curRadio->Retain();
    }
    if(_curRadio!=0){
        _curRadio->Release();
    }
    _curRadio = curRadio;
}
RadioBLLDelegate *RadioBll::delegate() const
{
    return _delegate;
}

void RadioBll::setDelegate(RadioBLLDelegate *delegate)
{
    _delegate = delegate;
}



void RadioBll::getRadios()
{
    static QMutex mutex;
    static EZTally::EZTallyArray<RadioModel*> *radios=0;


    GetRadioThread *thread = new GetRadioThread(&mutex,&radios);

    connect(thread,SIGNAL(rungetRadioFinish(EZTally::EZTallyArray<RadioModel*> *,int)),
            this,SLOT(getRadioFinish_SLOT(EZTally::EZTallyArray<RadioModel*>*,int)));

    thread->start();

}
void RadioBll::getRadioFinish_SLOT(EZTally::EZTallyArray<RadioModel*> *radios,int error)
{
//    GetRadioThread *thread = (GetRadioThread*)sender();
//    delete thread;
    emit getRadioFinish_SIG(radios,error);
}


EZTally::EZTallyAutoPtr  RadioBll::ParseRadioFromNetStr(const QByteArray &bytearray,int *outError)
{
    EZTally::EZTallyAutoPtr ptr;
    int error = 0;

    QJsonParseError err;
    QJsonDocument document = QJsonDocument::fromJson(bytearray,&err);
//            qDebug () << document << document.isArray() << document.isNull() << document.isEmpty() << err;
    if(document.isObject()){
        QJsonObject rootObj = document.object();
        int status = rootObj["status"].toInt();
        if(status==1){
            EZTally::EZTallyArray<RadioModel*> *arr = new EZTally::EZTallyArray<RadioModel*>();
            ptr.Set(arr);
            QJsonArray fmarr = rootObj["data"].toArray();
            QJsonArray::Iterator iter = fmarr.begin();
            while (iter != fmarr.end()) {
                QJsonObject fmobj = (*iter).toObject();

                RadioModel *radio = new RadioModel();
                radio->setAddtime( fmobj["addtime"].toString() );
                radio->setBanner(fmobj["banner"].toString());
                radio->setClassid(fmobj["classid"].toInt());
                radio->setClassname(fmobj["classname"].toString());
                radio->setDescription(fmobj["description"].toInt());
                radio->setFmid(fmobj["fmid"].toInt());
                radio->setFmname(fmobj["fmname"].toString());
                radio->setFmtype(fmobj["fmtype"].toInt());
                radio->setHeat(fmobj["heat"].toInt());
                radio->setImgurl(fmobj["imgurl"].toString());
                radio->setIsnew(fmobj["isnew"].toInt());

                arr->AddObject(radio);
                radio->Release();

                iter++;

            }

            arr->Release();
        }else{
            error = -2;
        }
    }else{
        error = -1;
    }

    if(outError){
        *outError = error;
    }
    return ptr;
}

EZTally::EZTallyAutoPtr RadioBll::ParseRadioSongsFromNetstr(const QByteArray &bytes,int *outError,QString **outOffset)
{
    EZTally::EZTallyAutoPtr ptr;
    int error = 0;

    QJsonDocument document = QJsonDocument::fromJson(bytes,0);
    if(document.isObject()){
        QJsonObject rootObj = document.object();
        int status = rootObj["status"].toInt();
        QJsonArray fmarr = rootObj["data"].toArray();
        if(status==1 && fmarr.count()>0){

            EZTally::EZTallyArray<SongModel*> *arr = new EZTally::EZTallyArray<SongModel*>();
            ptr.Set(arr);

            QJsonObject songObj = fmarr.at(0).toObject();
            QString offset = songObj["offset"].toString();
            if(outOffset){
                *outOffset = new QString(offset);
            }
            QJsonArray songsArr = songObj["songs"].toArray();
            QJsonArray::Iterator iter = songsArr.begin();
             while (iter != songsArr.end()){
                 QJsonObject j_song = (*iter).toObject();

                 SongModel *song = new SongModel();
                 song->setSid( j_song["sid"].toInt() );
                 song->setTime( j_song["time"].toInt() );
                 song->setTitle(j_song["name"].toString());
                 if(j_song.find("hash")!=j_song.end()){
                     QString key(songHash_normal);
                     SongModel::Quality quality = SongModel::Quality(j_song["hash"].toString(),j_song["size"].toInt());
                     song->setQualityWithKey(key,quality );
                 }
                 if(j_song.find("m4ahash")!=j_song.end()){
                     QString key(songHash_m4a);
                     SongModel::Quality quality = SongModel::Quality(j_song["m4ahash"].toString(),j_song["m4asize"].toInt());
                     song->setQualityWithKey(key,quality);
                 }
                 if(j_song.find("320hash")!=j_song.end()){
                     QString key(songHash_320);
                     SongModel::Quality quality = SongModel::Quality(j_song["320hash"].toString(),j_song["320size"].toInt());
                     song->setQualityWithKey(key,quality);
                 }
                 if(j_song.find("hash_ape")!=j_song.end()){
                     QString key(songHash_ape);
                     SongModel::Quality quality = SongModel::Quality(j_song["hash_ape"].toString(),j_song["filesize_ape"].toInt());
                     song->setQualityWithKey(key,quality);
                 }


                 arr->AddObject(song);
                 song->Release();

                 iter++;
             }

             arr->Release();
        }else{
            error = -2;
        }
    }else{
        error = -1;
    }
    if(outError){
        *outError = error;
    }
    return ptr;
}


//![GetRadioThread]
//!
GetRadioThread::GetRadioThread(QMutex *mutex_,EZTally::EZTallyArray<RadioModel*> **radios_):
    QThread(0)
{
    mutex = mutex_;
    radios = radios_;
    QObject::connect(this,SIGNAL(finished()),this,SLOT(deleteLater()));
}
GetRadioThread::~GetRadioThread()
{

}

void GetRadioThread::run()
{
    mutex->lock();
    if(*radios==0){//get radios from network
        QString urlStr(tr("http://lib3.service.kugou.com/index.php?cmd=12&ver=4000&pid=ios"));
        QUrl url(urlStr);
        QNetworkRequest request(url);
        QNetworkAccessManager *manager = new QNetworkAccessManager();
        QEventLoop loop;
        QObject::connect(manager,SIGNAL(finished(QNetworkReply*)),&loop,SLOT(quit()));
        QNetworkReply *reply = manager->get(request);
        loop.exec();
        QByteArray bytearray = reply->readAll();


//        QVariant varian(QString(str.c_str()) );
        int parseError = 0;

        EZTally::EZTallyAutoPtr ptr = RadioBll::ParseRadioFromNetStr(bytearray,&parseError);
        if(parseError==0){
            *radios = (EZTally::EZTallyArray<RadioModel*>*)(ptr.Get()->Retain());
        }
         emit rungetRadioFinish(*radios,0);
    }else{//local has radios
        emit rungetRadioFinish(*radios,0);
    }
    mutex->unlock();
}
//! //[GetRadioThread]


